package yartiss.engine.simulation.scheduling.policies.tools;

import yartiss.engine.simulation.IEnergyProfile;
import yartiss.engine.simulation.system.ITask;
import yartiss.engine.simulation.system.ITaskSet;
import yartiss.engine.simulation.system.SystemMetrics;

public class FPSlackEnergyManager1 {

	private FPSlackTimeManager timeManager = new FPSlackTimeManager();
	/**
	 * 
	 * @param t
	 * @param taskset
	 * @param energyProfile
	 * @return
	 */
	boolean log = false;
	long debug = 21931;

	public long getSlackEnergy(long t, ITaskSet taskset, IEnergyProfile energyProfile) {

		if (log)
			System.out.println("============================================================ slack start");

		ITask higherPriorityTask_t = taskset.getActiveTasks(t).first();

		long dk = SystemMetrics.effectiveDeadline(higherPriorityTask_t, taskset, higherPriorityTask_t.getNextAbsoluteDeadline(t));
		long slack = Long.MAX_VALUE;

		if (log)
			System.out.println("--------------slack energy for : Pi=" + higherPriorityTask_t.getPriority() + "/Ti=" + higherPriorityTask_t.getPeriod()
					+ " : t=" + t + " dk=" + dk + "   di=" + higherPriorityTask_t.getNextAbsoluteDeadline(t));

		for (ITask task_i : taskset.getHeadSet(higherPriorityTask_t, false)) {

			long xi = task_i.isActivationTime(t) ? t - 1 : t;

			do {
				long di = -1, slack_i = -1;

				xi = task_i.getNextActivation(xi);
				if (xi > t && xi < dk) {

					di = task_i.getNextAbsoluteDeadline(xi);
					di = SystemMetrics.effectiveDeadline(task_i, taskset, di);

					slack_i = slack_i(t, xi, dk, di, taskset, task_i, higherPriorityTask_t, energyProfile);

					if (log)
						System.out.println(task_i.getPriority() + " xi=" + xi + " di=" + di + " se_i=" + slack_i);

					slack = Math.min(slack, slack_i);
				}

			} while (xi < dk);

		}

		if (log)
			System.out.println("slack=" + slack);
		return slack;
	}

	/**
	 * 
	 * @param t
	 *            current time
	 * @param xi
	 *            activation time of considered job
	 * @param dk
	 *            effective deadline of highest priority task at time t
	 * @param di
	 *            effective deadline of considered job
	 * @param taskset
	 *            the task set
	 * @param task_i
	 *            the considered task
	 * @param task_k
	 *            highest priority task at time t
	 * @param energyProfile
	 *            the energy profile
	 * @return the task i job ?level slack energy at time t
	 */
	private long slack_i(long t, long xi, long dk, long di, ITaskSet taskset, ITask task_i, ITask task_k, IEnergyProfile energyProfile) {

		if (log && t == debug)
			System.out.println("*** t_" + task_i.getPriority());

		long slack = energyProfile.getCurrentEnergyLevel() + energyProfile.howMuchCanRecharge(di - t);

		if (log)
			System.out.println(t + " : slack[" + t + "," + di + "]=" + slack);
		
		for (ITask task_j : taskset.getHeadSet(task_k, false)) {

			long xj = task_i.isActivationTime(t) ? t - 1 : t;
			do {
				long ei = 0;
				xj = task_j.getNextActivation(xj);
				if (xj > t && xj < di) {
					if (task_j.getPriority() <= task_i.getPriority()) {
						ei = task_j.getWcee();

						if (log && t == debug)
							System.out.println("yes :__+prio_t" + task_j.getPriority() + "__xj=" + xj + " di=" + di);
					} else if (xj < xi) {

						ei = 0;
						long st = timeManager.getSlackTime(xj, taskset);

						if (st < xi - xj) {
							ei = task_j.getWcee();
							if (log)
								System.out.print("yes :");
						} else {
							ei = 0;
							if (log)
								System.out.print("no  :");
						}
						if (log)
							System.out.println("__-prio_t" + task_j.getPriority() + "_xj=" + xj + " st=" + st + "<" + (xi - xj));
					}
					slack -= ei;
				}

			} while (xj < Math.min(dk, di));

			if (task_j == task_i)
				slack += task_i.getWcee();

			if (task_j.getPriority() > task_i.getPriority() && task_j.isActive()) {
				long st = timeManager.getSlackTime(t, taskset);
				// System.out.println("st2="+st);
				if (st < xi - t) {
					slack -= task_j.getRemainingCost() * task_j.getEnergyConsumptionRate();
					if (log)
						System.out.print("yes :");
				} else if (log)
					System.out.print("no  :");

				if (log)
					System.out.println("__-prio_avant_t_t" + task_j.getPriority() + " rc=" + task_j.getRemainingCost() + " st=" + st + "<" + (xi - t));
			}
		}

		slack += task_i.getWcee();

		if (log && t == debug)
			System.out.println(xi + " : " + slack);

		return slack;
	}

	// public boolean isSlackEnergyDefined(long t, ITaskSet taskset,
	// SortedSet<Task> activeTasks) {
	// if(activeTasks.isEmpty())return false;
	// Task higherPriorityTask_t = activeTasks.first();
	// long dk = higherPriorityTask_t.getNextAbsoluteDeadline(t);
	//
	// if(log)System.out.println("##### "+dk+" t="+t+" tache="+higherPriorityTask_t.getPriority());
	// boolean is = false;
	// for (Task task : taskset.getHeadSet(higherPriorityTask_t, false)) {
	// if(task.isActivationTime(t)){
	// if(log)System.out.println("##### non c pas lui");
	// return false;
	// }
	// if(!is){
	// long xi = task.getNextActivation(t);
	// if(xi > t && xi < dk){
	// if(log
	//
	// )System.out.println("##### time="+t+"  tk="+higherPriorityTask_t.getPriority()+" peut etre se � cause de : t"+task.getPriority()+" x="+xi+" dk="+dk);
	// is = true;
	// }
	// }
	// }
	// if(is && log)System.out.println("##### oui c lui");
	// return is;
	// }

}
